package io.xxx.xbutler.service;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hy.corecode.idgen.WFGIdGenerator;
import io.xxx.xbutler.common.ApplicationException;
import io.xxx.xbutler.data.SystemOperationMapper;
import io.xxx.xbutler.data.TaskItemMapper;
import io.xxx.xbutler.data.TaskMapper;
import io.xxx.xbutler.domain.SystemOperation;
import io.xxx.xbutler.domain.User;
import io.xxx.xbutler.domain.task.Task;
import io.xxx.xbutler.domain.task.TaskItem;
import io.xxx.xbutler.domain.task.TaskStatus;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class TaskService {

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private WFGIdGenerator idGenerator;

    @Resource
    private TaskMapper taskMapper;

    @Resource
    private TaskItemMapper taskItemMapper;

    @Resource
    private TransactionTemplate transactionTemplate;

    @Resource
    private SystemOperationMapper systemOperationMapper;

    public Page<Task> list(Task task, Page<Task> page) {
        LambdaQueryWrapper<Task> wrapper = new LambdaQueryWrapper<>();
        if (task.getId() != null) {
            wrapper.eq(Task::getId, task.getId());
        }
        if (StringUtils.hasText(task.getName())) {
            wrapper.like(Task::getName, task.getName());
        }
        if (task.getAreaId() != null) {
            wrapper.eq(Task::getAreaId, task.getAreaId());
        }
        if (task.getOperateAreaId() != null) {
            wrapper.eq(Task::getOperateAreaId, task.getOperateAreaId());
        }
        if (StringUtils.hasText(task.getCreatedName())) {
            wrapper.like(Task::getCreatedName, task.getCreatedName());
        }
        if (task.getStatus() != null) {
            wrapper.eq(Task::getStatus, task.getStatus());
        }

        return taskMapper.selectPage(page, wrapper);
    }

    public Task get(Long id) {
        Task task = taskMapper.selectById(id);
        if (task != null) {
            LambdaQueryWrapper<TaskItem> wrapper = new LambdaQueryWrapper<TaskItem>()
                    .eq(TaskItem::getTaskId, id);
            List<TaskItem> taskItems = taskItemMapper.selectList(wrapper);
            Map<Integer, List<TaskItem>> items = taskItems.stream()
                    .collect(Collectors.groupingBy(TaskItem::getPsn));
            task.setItems(new ArrayList<>(items.values()));
        }
        return task;
    }

    public void create(Task task, List<TaskItem> items, User user) {
        SystemOperation operation = new SystemOperation()
                .setId(idGenerator.next())
                .setUserId(user.getId())
                .setUserName(user.getName())
                .setActionType("task.create")
                .setActionName("创建任务")
                .setRequestBody(JSON.parseObject(JSON.toJSONString(task)))
                .setCreatedTime(LocalDateTime.now());

        transactionTemplate.executeWithoutResult(_ -> {
            taskMapper.insert(task);
            taskItemMapper.insert(items);
            systemOperationMapper.insert(operation);
        });
    }

    public void update(Task task, List<TaskItem> items, User user) {
        Long taskId = task.getId();
        RLock lock = redissonClient.getLock("lock:task:update:" + taskId);
        try {
            if (!lock.tryLock()) {
                log.info("任务正在被其他人修改[taskId:{}]", taskId);
                throw new ApplicationException(100_001, "任务正在被其他人修改");
            }
            LambdaQueryWrapper<TaskItem> wrapper = new LambdaQueryWrapper<TaskItem>()
                    .eq(TaskItem::getTaskId, taskId);

            SystemOperation operation = new SystemOperation()
                    .setId(idGenerator.next())
                    .setUserId(user.getId())
                    .setUserName(user.getName())
                    .setActionType("task.update")
                    .setActionName("更新任务")
                    .setRequestBody(JSON.parseObject(JSON.toJSONString(task)))
                    .setCreatedTime(LocalDateTime.now());

            transactionTemplate.executeWithoutResult(_ -> {
                int count = taskMapper.updateById(task);
                if (count > 0) {
                    taskItemMapper.delete(wrapper);
                    taskItemMapper.insert(items);
                    systemOperationMapper.insert(operation);
                }
            });
        } finally {
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
    }

    public void delete(Long taskId, User user) {
        LambdaQueryWrapper<TaskItem> wrapper = new LambdaQueryWrapper<TaskItem>()
                .eq(TaskItem::getTaskId, taskId);

        SystemOperation operation = new SystemOperation()
                .setId(idGenerator.next())
                .setUserId(user.getId())
                .setUserName(user.getName())
                .setActionType("task.delete")
                .setActionName("删除任务")
                .setRequestParams(new JSONObject() {{
                    put("taskId", taskId);
                }})
                .setCreatedTime(LocalDateTime.now());
        transactionTemplate.executeWithoutResult(_ -> {
            taskMapper.deleteById(taskId);
            taskItemMapper.delete(wrapper);
            systemOperationMapper.insert(operation);
        });
    }

    /**
     * 取消任务，只将任务的状态置为取消状态，任务在执行的过程中需要检查任务状态。
     */
    public void cancel(Long taskId, User user) {
        LocalDateTime now = LocalDateTime.now();
        LambdaUpdateWrapper<Task> wrapper = new LambdaUpdateWrapper<Task>()
                .set(Task::getStatus, TaskStatus.CANCELED)
                .set(Task::getUpdatedId, user.getId())
                .set(Task::getUpdatedName, user.getName())
                .set(Task::getUpdatedTime, now)
                .eq(Task::getId, taskId);

        SystemOperation operation = new SystemOperation()
                .setId(idGenerator.next())
                .setUserId(user.getId())
                .setUserName(user.getName())
                .setActionType("task.cancel")
                .setActionName("取消任务")
                .setRequestParams(new JSONObject() {{
                    put("taskId", taskId);
                }})
                .setCreatedTime(now);
        transactionTemplate.executeWithoutResult(_ -> {
            taskMapper.update(wrapper);
            systemOperationMapper.insert(operation);
        });
    }
}
